//This is the application class.  It is composed of various interchangeable
//components that allow the application to function in different ways.

#ifndef _HELIX_APPLICATION_H_
#define _HELIX_APPLICATION_H_

#include "Helix.h"
#include "Window.h"
#include "Input.h"
#include "HObject.h"
#include "Timer.h"
#include "Renderer.h"
#include "Updater.h"

namespace helix		//Put this in the helix namespace
{

	/**
	*	The main class for the engine.  Maintains window type, input, timer, and
	*   acts as the glue that ties everything together.  Implemented as a singleton
	*   so that filthy users can't ruin things be creating more than one.
	*/
	class MY_CLASS Application : public HObject
	{
	private:
		WNDCLASS	wc;							// Windows Class Structure
		HINSTANCE   hInstance;					//handle to the application

		bool running;				//is the game running?
		bool active;				//is the game window active (does it have focus)?

		Window *appWindow;			// a pointer to the window object
		Input *appInput;			// a pointer to the input object
		Timer *appTimer;			// a pointer to the timer object

		Renderer *appRenderer;		// a pointer to the rendering object (that does rendering code)
		Updater *appUpdater;		// a pointer to the updating object (that does updating code)

		static Application *thisApp;

		Application();				//make the constructor private so that the user can't create more than one
		~Application();
	public:

		/** Use this as the first parameter of initApp to use an OpenGL window */
		static const int OPEN_GL_WINDOW = 1;	
		/** Use this as the first parameter of initApp to use a DirectX window */
		static const int DIRECTX_WINDOW = 2;	

		/** Get the current window object.  Note that the window is created when the initApp method is
		    invoked.  There is no way to change window objects without restarting the application.
		
			\return the current window object 
		*/
		Window *window()	
		{
			return appWindow;					
		}

		/** Returns the current instance of the application */
		static Application* getInstance();
		
		/** Initialize the application from a file
			\todo IMPLEMENT THIS FUNCTION!!!
			\param fileName The location of the file that contains config information 
			\return true if a window was created	
		*/
		bool initApp(const char* fileName);

		/** Initialize the application from a parameter list
			\param windowType 
						- Application::OPEN_GL_WINDOW Create a window with an OpenGL rendering context
						-  
			\param title The title of the window
			\param width The width (in pixels) of the window
			\param height The height (in pixels) of the window
			\param bpp The bits per pixel of the the rendering context
			\param fov The field of view of the window (in degrees)
			\param fullscreen Whether or not to create the window in fullscreen mode
			\return true if a window was created
			\todo Add support for DirectX as a window type
		*/
		bool initApp(int windowType,const char* title,int width,int height,int bpp,float fov,bool fullScreen);

		void setInput(Input *input);				//set the input object
		Input *input();								//get the input object
		void deleteInput();							//delete the current input object

		void setTimer(Timer *timer);				//set the timer object that gets updated every frame
		Timer *timer();								//get the timer object
		void deleteTimer();							//delete the current timer object

		void setUpdater(Updater *updater);			//set the updater object that gets called every frame
		Updater *updater();							//get the updater object
		void deleteUpdater();						//delete the current updater object
		void replaceUpdater(Updater *updater);		//replace the current updater object (old object is deleted)

		void setRenderer(Renderer *renderer);		//set the renderer object that gets called every frame
		Renderer *renderer();						//get the renderer object
		void deleteRenderer();						//delete the current renderer object
		void replaceRenderer(Renderer *renderer);	//replace the current renderer object (old object is deleted)


		bool runMainLoop(MSG *msg);

		void exitApp(int exitCode);

		void destroyApp();

		static LRESULT handleMessages(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam);	// Additional Message Information
	};

}  //End the helix namespace

#endif